﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WordNet.Core;
using WordNet.Core.DataContract;
using WordNet.Core.ElementContracts;

namespace Parsers
{
    internal class NounAdverbHandler:IParserHandler<ISynset>
    {
        protected int _index = 0;
        protected POS _synsetType;
        protected bool _isAdjSat;
       
        protected POS GetSynsetType(string[] tokens)
        {
            const int SynsetTypePosition = 2;
            _isAdjSat = tokens[SynsetTypePosition][0] == 's';
            return POS.GetPartOfSpeech(tokens[SynsetTypePosition][0]);
        }
        
        protected int GetOffset(string[] tokens)
        {
            return Convert.ToInt32(tokens[_index++]);
        }
       
        protected ILexFile GetLexFile(string[] tokens)
        {
            int lex_num = Convert.ToInt32(tokens[_index++]);
            ILexFile lexFile = LexFile.GetLexicalFile(lex_num);
            if (lexFile == null)
                lexFile = UnknownLexFile.GetUnknownLexicalFile(lex_num);
            return lexFile;
        }

        // consume pos and create synset id using offset and pos
        protected ISynsetID GetSynsetId(int offset, string[] tokens)
        {
            char pos_symbol = tokens[_index++][0];
            POS pos = POS.GetPartOfSpeech(pos_symbol);
            return new SynsetID(offset, pos);
        }

        protected virtual IWordBuilder[] GetWords(string[] tokens)
        {
            // Get words w_cnt
            int wordCount = Convert.ToInt32(tokens[_index++], 16);
            String lemma;
            int lexID;
            IWordBuilder[] wordProxies = new WordBuilder[wordCount];
            for (int i = 0; i < wordCount; i++)
            {
                // consume next word
                lemma = tokens[_index++];
                // parse lex_id
                lexID = Convert.ToInt32(tokens[_index++], 16);

                wordProxies[i] = new WordBuilder(i + 1, lemma, lexID, null);

            }
            return wordProxies;
        }

        protected Dictionary<IPointer, List<ISynsetID>> GetPointers(string[] tokens, IWordBuilder[] wordProxies)
        {
            // Get pointer count
            int pointerCount = int.Parse(tokens[_index++]);

            // Get pointers
            Dictionary<IPointer, List<ISynsetID>> synsetPointerMap = null;
            IPointer pointer_type;
            int target_offset;
            POS target_pos;
            int source_target_num, source_num, target_num;
            List<ISynsetID> pointerList = null;
            IWordID target_word_id;
            ISynsetID target_synset_id;
            for (int i = 0; i < pointerCount; i++)
            {
                // get pointer symbol
                pointer_type = Pointer.GetPointerType(tokens[_index++], _synsetType); ;

                // get synset target offset
                target_offset = int.Parse(tokens[_index++]);

                // get target synset part of speech
                target_pos = POS.GetPartOfSpeech(tokens[_index++][0]);

                target_synset_id = new SynsetID(target_offset, target_pos);

                // get source/target numbers
                source_target_num = Convert.ToInt32(tokens[_index++], 16);

                // this is a semantic pointer if the source/target numbers are
                // zero
                if (source_target_num == 0)
                {
                    if (synsetPointerMap == null)
                        synsetPointerMap = new Dictionary<IPointer, List<ISynsetID>>();
                    if (synsetPointerMap.ContainsKey(pointer_type))
                        pointerList = synsetPointerMap[pointer_type];
                    else
                    {
                        pointerList = new List<ISynsetID>();
                        synsetPointerMap.Add(pointer_type, pointerList);

                    }

                    pointerList.Add(target_synset_id);
                }
                else
                {
                    // this is a lexical pointer
                    source_num = source_target_num / 256;
                    target_num = source_target_num & 255;
                    target_word_id = new WordID(target_synset_id, target_num);
                    wordProxies[source_num - 1].AddRelatedWord(pointer_type, target_word_id);

                }
            }

            return synsetPointerMap;
        }
       
        protected virtual void AddFrame(string[] tokens, IWordBuilder[] wordProxies) { }
        protected string GetGloss(string line)
        {
            // Get gloss
            String gloss = "";
            int index = line.IndexOf('|');
            if (index > 0)
                gloss = line.Substring(index + 2).Trim();
            return gloss;
        }
       
        public ISynset Parse(string[] tokens, string line)
        {
            _synsetType = GetSynsetType(tokens);
            int offset = GetOffset(tokens);
            ILexFile lexFile = GetLexFile(tokens);
            ISynsetID synsetId = GetSynsetId(offset, tokens);
            IWordBuilder[] wordProxies = GetWords(tokens);
            Dictionary<IPointer, List<ISynsetID>> pointers = GetPointers(tokens, wordProxies);
            AddFrame(tokens, wordProxies);
            string gloss = GetGloss(line);

            // is adjective satelite?
            //  bool isAdjSat = (synsetId.GetPartOfSpeech().Tag == 's');

            // special cases: head synset without antonyms
            bool isAdjHead = !_isAdjSat && lexFile.Number == 0;

            // create synset and words
            List<IWordBuilder> words = new List<IWordBuilder>(wordProxies);
            return new Synset(synsetId, lexFile, _isAdjSat, isAdjHead, gloss, words, pointers);
        }
    }
}
